#include "log.hpp"
#include "buffer.hpp"
#include "socket.hpp"
#include "channel.hpp"
#include "poller.hpp"
#include "eventLoop.hpp"
#include "connection.hpp"
#include "acceptor.hpp"
#include "loopThread.hpp"
#include "loopThreadPool.hpp"
#include "tcpServer.hpp"

/*
传统的tcpserver 一般都是一个主线程负责监听新连接到来 有连接到来时就分配一个线程对该连接进行管理和业务逻辑处理
如果客户端不关闭连接且长久保持通信状态 那么这个线程将一直占用内存资源 当服务器存在大量客户端连接时 内存资源会面临不足的问题

利用epoll模型对连接进行事件监控可以解决上面的问题 如果连接没有事件到来 就不会创建线程占用内存资源
当连接有事件到来时 才会创建一个线程对这一批事件进行处理 处理完毕后会释放线程 不会一直占用内存资源
这种模式称为单reactor单线程模式 该模式也存在一些问题 当业务处理逻辑较为复杂 需要较多时间进行处理时
如果只分配一个线程对一批事件进行处理 就会导致这批事件的处理时间过长 特别是排在就绪队列后面的那些事件
需要等待的时间更长 客户端的请求响应时间就会特别长 从而过早达到性能瓶颈

而单reactor多线程模式可以缓解上面的问题 同时分配多个线程对同一时间到来的一批事件进行处理 这样一来就减少了客户端的等待时间
但由于只有一个主线程对所有连接进行事件监控 下一批事件必须等待上一批事件处理完成之后才能进行处理
如果此时有一批新连接到来 这批新连接无法被立即接收 因此这种模式也容易达到性能瓶颈

多reactor多线程模式有效解决了上述的所有问题 多个线程对连接进行事件监控(可以一个线程监控一个或多个连接) 同时多个线程对事件进行处理
这种高并发的处理机制最大限度地利用了服务器的资源
*/

void testLog()
{
    LOG(INF, "this is a log %d", 123);
}

void testBuffer()
{
    //测试WriteString ReadAsString 以及moveWriter moveReader
    // Buffer buf1;
    // std::string s = "hello";
    // buf1.WriteString(s);
    // std::cout << buf1.getAbleReadSize() << std::endl;

    // std::string tmp;
    // if (!buf1.ReadAsString(tmp, buf1.getAbleReadSize()))
    //     return -1;
    // std::cout << tmp << std::endl;
    // std::cout << buf1.getAbleReadSize() << std::endl;

    //测试ReadAsBuffer
    // buf1.WriteString(s);
    // Buffer buf2;
    // if (!buf1.ReadAsBuffer(buf2, buf1.getAbleReadSize()))
    //     return -1;
    // std::cout << buf2.getAbleReadSize() << std::endl;
    // if (!buf2.ReadAsString(tmp, buf2.getAbleReadSize()))
    //     return -1;
    // std::cout << tmp << std::endl;
    // std::cout << buf1.getAbleReadSize() << std::endl;
    // std::cout << buf2.getAbleReadSize() << std::endl;

    //测试makeAbleWrite getLine
    Buffer buf;
    std::string s = "hello";
    for (int i = 0; i < 500; i++)//写入超过1024的数据测试makeAbleWrite
    {
        std::string tmp = s + std::to_string(i) + "\n";
        buf.WriteString(tmp);
    }
    std::string tmp;
    while ((tmp = buf.getLine()) != "")
    {
        std::cout << tmp;
    }
}

void testSocket()
{
    Socket listensock;
    if (!listensock.createServer(8080))
        return;

    Socket sock(listensock.Accept());
    if (sock.getFd() == -1) // accept failed
        return;
    while (true)//只对一个连接进行处理
    {
        char buffer[1024] = {0};
        int n = sock.Recv(buffer, sizeof buffer - 1, 0);
        if (n == -1)
            return;
        buffer[n - 1] = 0; // 把telnet客户端输入的换行覆盖掉
        LOG(DEG, "client say: %s", buffer);
        std::string res = "server echo: " + std::string(buffer) + "\n";
        n = sock.Send(res.c_str(), res.size(), 0);
        if (n == -1)
            return;
    }
}

EventLoop base_loop;
LoopThreadPool* loop_pool;
std::unordered_map<uint64_t, ConnectionPtr> connections;
uint64_t cid = 0;


// void handleClose(Channel* channel)
// { 
//     channel->removeEventMonitor(); 
//     LOG(DEG, "close fd: %d", channel->getFd());
//     close(channel->getFd());
//     delete channel;//TODO: 后续可能不在此处delete
// }

// void handleRead(Channel* channel)
// {
//     char buf[1024] = {0};//命名不要与宏函数LOG中的buffer重复
//     int n = recv(channel->getFd(), buf, sizeof buf - 1, 0);
//     if (n <= 0)//客户端关闭或读取发生错误
//     {
//         handleClose(channel);
//         LOG(DEG, "client quit");
//         return;
//     }
//     buf[n - 1] = 0;//-1是为了覆盖掉换行
//     LOG(DEG, "client say: %s", buf);
//     channel->monitorWrite();//设置写事件监控
// }

// void handleWrite(Channel* channel)
// {
//     const char* response = "hello client, I'm server\n";
//     int n = send(channel->getFd(), response, strlen(response), 0);
//     if (n <= 0)
//     {
//         handleClose(channel);
//         return;
//     }
//     channel->cancelMonitorWrite();//取消写事件监控
// }

// void handleError(Channel* channel)
// {
//     LOG(DEG, "出现了一个异常事件");
//     handleClose(channel);
// }

// void handleEvents(EventLoop* loop, uint64_t id)//客户端连接一旦触发事件便刷新定时关闭任务的执行时间
// {
//     loop->refreshTimerTask(id);
// }

void OnConnect(const ConnectionPtr& connection)
{
    LOG(DEG, "establish a new connection, id: %d", connection->getConnectionId());
}

void OnClose(const ConnectionPtr& connection)
{
    LOG(DEG, "connection closed, id: %d", connection->getConnectionId());
}

void OnMessage(const ConnectionPtr& connection)//业务处理回调 处理输入缓冲区中的数据
{
    Buffer* buf = connection->getInBuffer();
    std::string message;
    buf->ReadAsString(message, buf->getAbleReadSize());
    LOG(DEG, "client say: %s", message.c_str());
    std::string response = "hello client, I'm server\n";
    connection->send(response.c_str(), response.size());//先将数据写入发送缓冲区中 再开启写事件监控 写事件触发时 将处理结果发送给客户端
}

void OnEvents(const ConnectionPtr& connection)
{
    LOG(DEG, "OnEvents execute");
}

void accepterCallback(int sockfd)
{
    //acceptor回调是在主线程中调用的
    cid++;
    ConnectionPtr connection(new Connection(loop_pool->getNextLoop(), cid, sockfd));//将新接收的通信连接挂到RR轮转到的LoopThread对象上
    connections.insert(std::make_pair(cid, connection));//将当前的connection添加到全局hash中 防止connection离开当前作用域后直接释放
    connection->setConnectedCallback(std::bind(OnConnect, std::placeholders::_1));//connection指针在channel调用事件回调时手动传入 需要用到占位符
    connection->setClosedCallback(std::bind(OnClose, std::placeholders::_1));
    connection->setMessageCallback(std::bind(OnMessage, std::placeholders::_1));
    //connection->setEventsCallback(std::bind(OnEvents, std::placeholders::_1));
    //设置非活跃连接超时关闭的定时任务 10s后没有收到客户端的消息便断开与客户端的连接
    //下面这两个函数内部会调用runInLoop 当前connection对象的loop与主线程id不匹配 主线程会将添加定时任务和设置读事件监控会被压入从线程loop的任务池 再唤醒evfd后处理s
    connection->enableInactiveRelease(10);//放到读事件监控之前 因为一旦开启监控 如果连接出现问题直接调用close回调 那么连接关闭后再设置非活跃连接超时释放就会出问题
    connection->establishConnection();//设置读事件监控 执行OnConnect回调
    //通信连接的读事件监控以及各种事件和任务处理都是在从线程中进行的
    LOG(DEG, "create a new connection");
}

void testAcceptor()
{
    loop_pool = new LoopThreadPool(&base_loop);
    loop_pool->setThreadCount(2);
    loop_pool->create();//创建两个从属线程 并绑定loop对象
    Acceptor acceptor(8080, &base_loop);
    acceptor.setAcceptorCallback(std::bind(accepterCallback, std::placeholders::_1));
    acceptor.listen();
    base_loop.start();//主线程只负责对监听套接字的读事件进行监控 当读事件到来时接收新连接
}

int main()
{
    TcpServer server(8080);
    server.setThreadCount(2);
    server.enableInactiveRelease(10);
    server.setConnectedCallback(OnConnect);
    server.setClosedCallback(OnClose);
    server.setMessageCallback(OnMessage);
    server.start();
    return 0;
}